package com.xingda.packing.rule;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xingda.packing.config.appset.AppSetParam;
import com.xingda.packing.domain.CacheLocation;
import com.xingda.packing.domain.ProductBox;
import com.xingda.packing.domain.ShuntProductionLine;
import com.xingda.packing.domain.Wheel;
import com.xingda.packing.minitor.entity.PkTaskInfo;
import com.xingda.packing.minitor.mapper.PkTaskInfoMapper;
import com.xingda.packing.rule.check.PackRuleCheckService;
import com.xingda.packing.rule.choose.ChooseService;
import com.xingda.packing.rule.shunt.ShuntService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Component
public class RuleUtilsV2 {

    @Resource
    private List<ChooseService> chooseList;
    @Resource
    private List<PackRuleCheckService> checkList;
    @Resource
    private ShuntService shuntService;
    @Resource
    private PkTaskInfoMapper taskInfoMapper;

    public boolean canPut(ProductBox productBox, Wheel wheel) {

        if (Objects.isNull(wheel)) {
            return false;
        }

        LambdaQueryWrapper<PkTaskInfo> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PkTaskInfo::getTaskId, productBox.getTaskId())
                .orderByAsc(PkTaskInfo :: getPutTime).orderByAsc(PkTaskInfo :: getId);

        List<PkTaskInfo> taskInfos = taskInfoMapper.selectList(wrapper);

        List<String> hasWheels = productBox.getLocationList().stream().
                filter(location -> location.getWheel() != null).map(l -> l.getWheel().getBarCode()).
                collect(Collectors.toList());

        if (taskInfos.size() != hasWheels.size()) {
            log.error("checkCanPut box:{}, taskInfoCount:{}, locationCount:{}", productBox.getBoxNo(), taskInfos.size(), hasWheels.size());
            log.error("checkCanPut taskInfo:{}", taskInfos.stream().map(PkTaskInfo::getWheelId).collect(Collectors.toList()));
            log.error("checkCanPut locationList:{}", hasWheels);
            return false;
        }

        if (!chooseList.stream().allMatch(chooseRule -> chooseRule.canChoose(productBox, wheel))) {
            return false;
        }

        productBox.prePutWheel(wheel);
        if (checkList.stream().allMatch(checkRule -> checkRule.inspect(productBox))) {
            return true;
        } else {
            productBox.clearPrePutWheel();
            return false;
        }
    }

    public boolean canShunt(ProductBox productBox, Wheel wheel) {
        return shuntService.canShunt(productBox, wheel);
    }


    /**
     * 最优选择方案
     * 1.从倒数第三个轮子开始，选择可放概率最大的优先，不区分是否重卷
     * 2.倒数第三个轮子之前，优先放重卷，多轮可放时，选时间靠前优先
     */
    public CacheLocation getOptimalWheel(ProductBox productBox, List<CacheLocation> cacheLocationList) {

        if (CollectionUtils.isEmpty(cacheLocationList)) {
            return null;
        }
        CacheLocation cacheLocation;
        if (productBox.getType() == 2) {
            return getOptimal3(productBox, cacheLocationList);
        } else if (productBox.getFloorLocationCount() - productBox.floorWheelCount() <= AppSetParam.probability_priority_last_num) {
            cacheLocation = getOptimal1(productBox, cacheLocationList);
        } else {
            cacheLocation = getOptimal2(cacheLocationList);
        }
        return cacheLocation;
    }

    private CacheLocation getOptimal3(ProductBox productBox, List<CacheLocation> cacheLocationList) {
        if (CollectionUtils.isEmpty(cacheLocationList)) {
            return null;
        }
        if (productBox.getRequireCount() == 3) {
            return cacheLocationList.stream().sorted(Comparator.comparing(CacheLocation::getNo).reversed()).collect(Collectors.toList()).get(0);
        } else {
            return cacheLocationList.get(0);
        }
    }

    /**
     * 优先方案1
     * 选择可放概率最大的优先，不区分是否重卷
     */
    private CacheLocation getOptimal1(ProductBox productBox, List<CacheLocation> cacheLocationList) {
        if (CollectionUtils.isEmpty(cacheLocationList)) {
            return null;
        }
        List<CacheLocation> canUseCacheLocation = cacheLocationList.stream().filter(CacheLocation::isOccupy).collect(Collectors.toList());
        CacheLocation cacheLocation = null;
        double temp_facotr = -1.0;
        for (CacheLocation cache : canUseCacheLocation) {
            double prob_factor = RuleProb.prob_factor(productBox, cache.getWheel());
            if (temp_facotr == -1.0) {
                temp_facotr = prob_factor;
                cacheLocation = cache;
            } else if (prob_factor > temp_facotr) {
                temp_facotr = prob_factor;
                cacheLocation = cache;
            }
        }
        return cacheLocation;
    }

    /**
     * 优先方案2
     * 选择时间靠前的轮子，优先重卷轮
     */
    private CacheLocation getOptimal2(List<CacheLocation> cacheLocationList) {
        if (CollectionUtils.isEmpty(cacheLocationList)) {
            return null;
        }
        //优先选择重卷轮
        List<CacheLocation> canUseCacheLocation = cacheLocationList.stream()
                .filter(CacheLocation::isOccupy)
                .filter(location -> location.getWheel().isAnew())
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(canUseCacheLocation)) {
            canUseCacheLocation = cacheLocationList.stream()
                    .filter(CacheLocation::isOccupy)
                    .collect(Collectors.toList());
        }
        CacheLocation cacheLocation = null;
        long temp_time = -1L;
        for (CacheLocation cache : canUseCacheLocation) {
            long time = cache.getPutTime().toEpochSecond(ZoneOffset.of("+8"));
            if (temp_time == -1L) {
                temp_time = time;
                cacheLocation = cache;
            } else if (time < temp_time) {
                temp_time = time;
                cacheLocation = cache;
            }
        }
        return cacheLocation;
    }

    public int randomShunt(ShuntProductionLine productionLine, int area, String line) {
        List<CacheLocation> leftOccupyLocation = productionLine.getPackProductionLine().getCacheArea().getOccupyLocation(1);
        List<CacheLocation> rightOccupyLocation = productionLine.getPackProductionLine().getCacheArea().getOccupyLocation(2);
        if (line.equals("6") || line.equals("5")) {
            if (leftOccupyLocation.size() > rightOccupyLocation.size()) {
                if (area == 3) {
                    return 2;
                } else {
                    return 1;
                }
            } else {
                if (area == 3) {
                    return 1;
                } else {
                    return 2;
                }

            }
        } else {
            if (leftOccupyLocation.size() > rightOccupyLocation.size()) {
                return 2;
            } else {
                return 1;
            }
        }

    }

}
